package main

import (
	"bytes"
	"compress/gzip"
	"crypto/aes"
	"crypto/cipher"
	"encoding/base64"
	"encoding/hex"
	"io"
	"strings"
	"unsafe"
)

func AesDecryptECB(encrypted []byte, key []byte) (decrypted []byte) {
	cipherf, _ := aes.NewCipher(generateKey(key))
	decrypted = make([]byte, len(encrypted))
	for bs, be := 0, cipherf.BlockSize(); bs < len(encrypted); bs, be = bs+cipherf.BlockSize(), be+cipherf.BlockSize() {
		if be > len(decrypted) || be > len(encrypted) || bs > len(decrypted) || bs > len(encrypted) {
			return []byte{}
		}
		cipherf.Decrypt(decrypted[bs:be], encrypted[bs:be])
	}

	trim := 0
	if len(decrypted) > 0 {
		trim = len(decrypted) - int(decrypted[len(decrypted)-1])
	}

	return decrypted[:trim]
}
func generateKey(key []byte) (genKey []byte) {
	genKey = make([]byte, 16)
	copy(genKey, key)
	for i := 16; i < len(key); {
		for j := 0; j < 16 && i < len(key); j, i = j+1, i+1 {
			genKey[j] ^= key[i]
		}
	}
	return genKey
}

//JSAesDecrypt AES解密。传入要解密的字符串。返回两个参数：参数1是解密后的字符串，参数2是是否解密成功。
//UngzipStr		GZIP解压字符串。传入要解密的字符串。返回两个参数：参数1是解密后的字符串，参数2是是否解密成功。
//GzipStr		Gzip压缩字符串。传入要压缩的字符串。返回两个参数：参数1是加密后的字符串，参数2是是否加密成功。

func AnyOverlap(x, y []byte) bool {
	return len(x) > 0 && len(y) > 0 &&
		uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
		uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
}

func InexactOverlap(x, y []byte) bool {
	if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
		return false
	}
	return AnyOverlap(x, y)
}

func b2a_hex(data []byte) (rt string) {
	rt = ""
	for _, v := range data {
		h := v >> 4
		switch h {
		case 0:
			rt = rt + "0"
			break
		case 1:
			rt = rt + "1"
			break
		case 2:
			rt = rt + "2"
			break
		case 3:
			rt = rt + "3"
			break
		case 4:
			rt = rt + "4"
			break
		case 5:
			rt = rt + "5"
			break
		case 6:
			rt = rt + "6"
			break
		case 7:
			rt = rt + "7"
			break
		case 8:
			rt = rt + "8"
			break
		case 9:
			rt = rt + "9"
			break
		case 10:
			rt = rt + "a"
			break
		case 11:
			rt = rt + "b"
			break
		case 12:
			rt = rt + "c"
			break
		case 13:
			rt = rt + "d"
			break
		case 14:
			rt = rt + "e"
			break
		case 15:
			rt = rt + "f"
			break
		}
		h = v << 4 >> 4
		switch h {
		case 0:
			rt = rt + "0"
			break
		case 1:
			rt = rt + "1"
			break
		case 2:
			rt = rt + "2"
			break
		case 3:
			rt = rt + "3"
			break
		case 4:
			rt = rt + "4"
			break
		case 5:
			rt = rt + "5"
			break
		case 6:
			rt = rt + "6"
			break
		case 7:
			rt = rt + "7"
			break
		case 8:
			rt = rt + "8"
			break
		case 9:
			rt = rt + "9"
			break
		case 10:
			rt = rt + "a"
			break
		case 11:
			rt = rt + "b"
			break
		case 12:
			rt = rt + "c"
			break
		case 13:
			rt = rt + "d"
			break
		case 14:
			rt = rt + "e"
			break
		case 15:
			rt = rt + "f"
			break
		}
	}
	return rt
}
func BytesCombine(pBytes ...[]byte) []byte {
	return bytes.Join(pBytes, []byte(""))
}
func add_to_16(data []byte) []byte {
	add := make([]byte, 0)
	ln := len(data) % 16
	if ln > 0 {
		add = make([]byte, 16-ln)
	}
	return BytesCombine(data, add)
}

func PKCS5Padding(cipherText []byte, blockSize int) []byte {
	padding := blockSize - len(cipherText)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(cipherText, padText...)
}

func JinanGongJiaoAesEncrypt(orig string) string {
	key := "0OHhMe1bNtGk32VH"

	aesBlockEncrypter, err := aes.NewCipher([]byte(key))
	content := PKCS5Padding([]byte(orig), aesBlockEncrypter.BlockSize())
	encrypted := make([]byte, len(content))
	if err != nil {
		return ""
	}
	aesEncrypter := cipher.NewCBCEncrypter(aesBlockEncrypter, []byte(key))

	aesEncrypter.CryptBlocks(encrypted, content)
	return base64.StdEncoding.EncodeToString(encrypted)
}
func JSAesEncryptShuifa(orig string) string {
	key := "sfjt1@sdtanpuhui.cn_0918"
	// 转成字节数组
	origData := []byte(orig)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()

	// 补全码
	origData = TangwgAESPKCS7Padding(origData, blockSize)

	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	// 创建数组
	cryted := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(cryted, origData)

	res := base64.StdEncoding.EncodeToString(cryted)

	res = strings.Replace(res, "/", "_", -1)
	res = strings.Replace(res, "+", ".", -1)
	return res
}
func JSAesDecryptShuifa(cryted string) (string, bool) {
	key := "sfjt1@sdtanpuhui.cn_0918"
	cryted = strings.Replace(cryted, "_", "/", -1)

	// 转成字节数组
	crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(crytedByte))
	if len(orig)%blockSize != 0 {
		return "", false
	}
	if len(orig) < len(crytedByte) {
		return "", false
	}
	if InexactOverlap(orig[:len(crytedByte)], crytedByte) {
		return "", false
	}

	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	ff := false
	orig, ff = TangwgAESPKCS7UnPadding(orig)
	return string(orig), ff
}
func JSAesEncryptCommon(orig string, key string, iv string) string {
	//key := "hello@sdtanpuhui.cn_1234"
	// 转成字节数组
	origData := []byte(orig)
	k := []byte(key)
	ik := []byte(iv)
	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 补全码
	origData = TangwgAESPKCS7Padding(origData, blockSize)
	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, ik[:blockSize])
	// 创建数组
	cryted := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(cryted, origData)

	res := base64.StdEncoding.EncodeToString(cryted)

	res = strings.Replace(res, "/", "_", -1)
	res = strings.Replace(res, "+", ".", -1)
	return res
}
func JSAesDecryptCommon(cryted string, key string, iv string) (string, bool) {
	//key := "hello@sdtanpuhui.cn_1234"
	cryted = strings.Replace(cryted, "_", "/", -1)
	cryted = strings.Replace(cryted, ".", "+", -1)

	// 转成字节数组
	crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
	k := []byte(key)
	ik := []byte(iv)
	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, ik)
	// 创建数组
	orig := make([]byte, len(crytedByte))
	if len(orig)%blockSize != 0 {
		return "", false
	}
	if len(orig) < len(crytedByte) {
		return "", false
	}
	if InexactOverlap(orig[:len(crytedByte)], crytedByte) {
		return "", false
	}

	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	ff := false
	orig, ff = TangwgAESPKCS7UnPadding(orig)
	return string(orig), ff
}

func JSAesEncryptOut(orig string) string {
	key := "lixin@sdtanpuhui.cn_0918"
	// 转成字节数组
	origData := []byte(orig)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 补全码
	origData = TangwgAESPKCS7Padding(origData, blockSize)
	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	// 创建数组
	cryted := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(cryted, origData)

	return hex.EncodeToString(cryted)
}

func JSAesDecryptOut(cryted string) (string, bool) {
	key := "lixin@sdtanpuhui.cn_0918"

	crytedByte, _ := hex.DecodeString(cryted)

	// 转成字节数组
	//crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(crytedByte))
	if len(orig)%blockSize != 0 {
		return "", false
	}
	if len(orig) < len(crytedByte) {
		return "", false
	}
	if InexactOverlap(orig[:len(crytedByte)], crytedByte) {
		return "", false
	}

	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	ff := false
	orig, ff = TangwgAESPKCS7UnPadding(orig)
	return string(orig), ff
}
func JSAesEncryptYear(orig string) string {
	key := "tangl@sdtanpuhui.cn_2024"
	// 转成字节数组
	origData := []byte(orig)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 补全码
	origData = TangwgAESPKCS7Padding(origData, blockSize)
	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	// 创建数组
	cryted := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(cryted, origData)

	res := base64.StdEncoding.EncodeToString(cryted)

	res = strings.Replace(res, "/", "_", -1)
	res = strings.Replace(res, "+", ".", -1)
	return res
}

func JSAesDecryptYear(cryted string) (string, bool) {
	key := "tangl@sdtanpuhui.cn_2024"
	cryted = strings.Replace(cryted, "_", "/", -1)
	cryted = strings.Replace(cryted, ".", "+", -1)
	// 转成字节数组
	crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(crytedByte))
	if len(orig)%blockSize != 0 {
		return "", false
	}
	if len(orig) < len(crytedByte) {
		return "", false
	}
	if InexactOverlap(orig[:len(crytedByte)], crytedByte) {
		return "", false
	}

	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	ff := false
	orig, ff = TangwgAESPKCS7UnPadding(orig)
	return string(orig), ff
}

func JSAesEncrypt(orig string) string {
	key := "hello@sdtanpuhui.cn_1234"
	// 转成字节数组
	origData := []byte(orig)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 补全码
	origData = TangwgAESPKCS7Padding(origData, blockSize)
	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	// 创建数组
	cryted := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(cryted, origData)

	res := base64.StdEncoding.EncodeToString(cryted)

	res = strings.Replace(res, "/", "_", -1)
	res = strings.Replace(res, "+", ".", -1)
	return res
}

func JSAesDecrypt(cryted string) (string, bool) {
	key := "hello@sdtanpuhui.cn_1234"
	cryted = strings.Replace(cryted, "_", "/", -1)
	cryted = strings.Replace(cryted, ".", "+", -1)
	// 转成字节数组
	crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(crytedByte))
	if len(orig)%blockSize != 0 {
		return "", false
	}
	if len(orig) < len(crytedByte) {
		return "", false
	}
	if InexactOverlap(orig[:len(crytedByte)], crytedByte) {
		return "", false
	}

	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	ff := false
	orig, ff = TangwgAESPKCS7UnPadding(orig)
	return string(orig), ff
}

func JSAesEncrypt2(orig string) string {
	key := "tang1@sdtanpuhui.cn_0918"
	// 转成字节数组
	origData := []byte(orig)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 补全码
	origData = TangwgAESPKCS7Padding(origData, blockSize)
	// 加密模式
	blockMode := cipher.NewCBCEncrypter(block, k[:blockSize])
	// 创建数组
	cryted := make([]byte, len(origData))
	// 加密
	blockMode.CryptBlocks(cryted, origData)

	res := base64.StdEncoding.EncodeToString(cryted)
	res = strings.Replace(res, "/", "_", -1)
	res = strings.Replace(res, "+", ".", -1)
	return res
}
func JSAesDecrypt2(cryted string) (string, bool) {
	key := "tang1@sdtanpuhui.cn_0918"
	cryted = strings.Replace(cryted, "_", "/", -1)
	cryted = strings.Replace(cryted, ".", "+", -1)
	// 转成字节数组
	crytedByte, _ := base64.StdEncoding.DecodeString(cryted)
	k := []byte(key)

	// 分组秘钥
	block, _ := aes.NewCipher(k)
	// 获取秘钥块的长度
	blockSize := block.BlockSize()
	// 加密模式
	blockMode := cipher.NewCBCDecrypter(block, k[:blockSize])
	// 创建数组
	orig := make([]byte, len(crytedByte))
	if len(orig)%blockSize != 0 {
		return "", false
	}
	if len(orig) < len(crytedByte) {
		return "", false
	}
	if InexactOverlap(orig[:len(crytedByte)], crytedByte) {
		return "", false
	}

	// 解密
	blockMode.CryptBlocks(orig, crytedByte)
	// 去补全码
	ff := false
	orig, ff = TangwgAESPKCS7UnPadding(orig)
	return string(orig), ff
}

// 补码
func TangwgAESPKCS7Padding(ciphertext []byte, blocksize int) []byte {
	padding := blocksize - len(ciphertext)%blocksize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

// 去码
func TangwgAESPKCS7UnPadding(origData []byte) ([]byte, bool) {
	length := len(origData)
	if length == 0 {
		return []byte{}, false
	}
	unpadding := int(origData[length-1])
	if (length - unpadding) < 0 {
		return []byte{}, false
	}
	return origData[:(length - unpadding)], true
}

func UngzipStr(str string) (string, bool) {

	//var out bytes.Buffer
	//encoded, _ := base64.StdEncoding.DecodeString(str)
	//ou1 := bytes.NewBuffer(encoded)
	//r, e := gzip.NewReader(ou1)
	//if e != nil {
	//	return str, false
	//}
	//io.Copy(&out, r)
	//return out.String(), true

	//return b.Bytes()

	decodeStr, err := base64.StdEncoding.DecodeString(str)
	if err != nil {
		return str, false
	}
	b := bytes.NewReader(decodeStr)
	var out bytes.Buffer
	r, e := gzip.NewReader(b)
	if e != nil {
		return str, false
	}
	io.Copy(&out, r)
	return string(out.Bytes()), true

}
